/*-
 * Copyright (c) 2007-2008 SINA Corporation, All Rights Reserved.
 *  Authors:
 *      Zhu Yan <zhuyan@staff.sina.com.cn>
 *
 * Sample library file store Implementation
 */
#include <libmemcached/memcached.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/uio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

#include "libmod.h"
#include "pic_download.h"
#include "log.h"

#define FILEOP_ERROR		mod_conf_priority

char mc_server[] = "mem.proxy.photo.sina.com.cn";

#ifndef MAX_PATH
#define MAX_PATH 1024
#endif

int mod_init(char *);

static int
write_file(const char *filename, struct iovec *iov, int n_iov)
{
	int fd;
	int retval;
	char tmp_fn[MAX_PATH];

	/* create a temp file to write */
	tmp_fn[0] = '\0';
	strncat(tmp_fn, filename, MAX_PATH - 1);
	strncat(tmp_fn, ".tmp", MAX_PATH - 1);
	
	fd = open(tmp_fn, O_RDWR|O_CREAT|O_EXCL, S_IRWXU|S_IRWXG|S_IROTH);
	
	if (fd < 0) {
		WLOG_ERR("filename: %s, error: %s",
			tmp_fn, strerror(errno));
		return (-1);
	}
	retval = writev(fd, iov, n_iov);
	if (retval < 0) {
		WLOG_ERR("filename: %s, error: %s",
			tmp_fn, strerror(errno));
		close(fd);
		remove(tmp_fn);
		return (-1);
	}
	close(fd);
	rename(tmp_fn, filename);
	WLOG_INFO("create file %s OK!", filename);

	return (0);
}


static ssize_t 
file_handler(WTI *wtip, CONN_INFO *cip, void *data, void **res)
{
	int retval;
	PIC_DATA *pdp = NULL;
	memcached_st *memp;
	memcached_st **mempp;
	int n_iov;
	DATA_BUFFER_NODE *dbnp = NULL;
	int file_size = 0;
	struct iovec iov[MAX_BLOCK_NUMBER];

	CSF_UNUSED_ARG(cip);
	CSF_UNUSED_ARG(wtip);

    if (res == NULL)
            return (PIPELINE_FAILED);

    mempp = (memcached_st**)res;
    memp = *mempp;
    if (memp == NULL)
            return (PIPELINE_FAILED);

    pdp = (PIC_DATA *)data;
    if (pdp == NULL)
            return (PIPELINE_FAILED);
	pdp = (PIC_DATA *)data;


	n_iov = 0;
	TAILQ_FOREACH(dbnp, &(pdp->data_buffer_head), data_buffer_entries) {
		iov[n_iov].iov_base = dbnp->data;
		iov[n_iov].iov_len = dbnp->data_len;
		n_iov++;
		file_size += dbnp->data_len;
		if (n_iov >= MAX_BLOCK_NUMBER) {
		    retval = memcached_delete (memp,
	                 pdp->pic_path, strlen(pdp->pic_path),
	                 0);
			return (PIPELINE_FAILED);
		}
	}
	pdp->data_len = file_size;

	if (file_size == 0) {
		WLOG_ERR("file: %s size is 0!", pdp->pic_path);
	    retval = memcached_delete (memp,
                     pdp->pic_path, strlen(pdp->pic_path),
                     0);
		return (PIPELINE_BREAK);
	}

	retval = write_file(pdp->pic_path, iov, n_iov);
	if (retval < 0)
		WLOG_ERR("Write file error!");
	else
		pdp->ok = 1;

    retval = memcached_delete (memp,
                         pdp->pic_url, strlen(pdp->pic_url),
                         0);

	if (retval != MEMCACHED_SUCCESS) {
		WLOG_ERR("memcached_delete() error: %s, url: %s", 
			memcached_strerror(memp, retval), pdp->pic_url);
		return(PIPELINE_FAILED);
	}
	return (PIPELINE_CONTINUE);
}

static ssize_t
file_init(void *arg, void **res)
{
	memcached_st *memp;
	memcached_st **mempp;
	memcached_return retval;

	CSF_UNUSED_ARG(arg);

	mempp = (memcached_st **)res;

	if (mempp == NULL)
	        return (PIPELINE_FAILED);

	memp = memcached_create(NULL);
	*mempp = memp;
	if (memp == NULL)
		return (PIPELINE_FAILED);
	/*
	if (!memcached_behavior_set (memp, MEMCACHED_BEHAVIOR_NO_BLOCK, 1))
	        return (PIPELINE_FAILED);
	if (!memcached_behavior_set (memp, MEMCACHED_BEHAVIOR_TCP_NODELAY, 1))
	        return (PIPELINE_FAILED);
	if (!memcached_behavior_set (memp, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, 3))
	        return (PIPELINE_FAILED);
	*/
	retval = memcached_server_add (memp, mc_server, 11211);
	if (retval != MEMCACHED_SUCCESS)
		return (PIPELINE_FAILED);

	return (PIPELINE_SUCCESS);
}

static void
file_deinit(void *arg, void *res)
{
	memcached_st *memp;
	CSF_UNUSED_ARG(arg);

	memp = (memcached_st *)res;
	if (memp == NULL) {
		WLOG_ERR("memcached_st is NULL!");
		return;
	}

	memcached_free(memp);
	return;
}


int 
mod_init(char *mod_name)
{
	CSF_UNUSED_ARG(mod_name);

	set_request_init(file_init);
	set_request_deinit(file_deinit);
	set_request_handler(file_handler);

	return (0);
}

